package org.micode.common.syslog;

import org.aspectj.lang.annotation.Aspect;
import org.micode.common.annotation.SysLog;
import org.micode.common.helper.I18nMsgHelper;
import org.micode.common.utils.BeanExtUtils;
import org.micode.common.domain.vo.SysLogVO;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.micode.common.utils.StringExtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

@Slf4j
public class SysLogAspect<T extends SysLogVO> {

    private Class<T> clazz;

    @Autowired
    private ISysLogSaver<T> sysLogSaver;

    public SysLogAspect() {
        Type superclass = getClass().getGenericSuperclass();
        log.trace("日志：superclass={}", superclass);
        ParameterizedType parameterizedType = null;
        if (superclass instanceof ParameterizedType) {
            parameterizedType = (ParameterizedType) superclass;
            Type[] typeArray = parameterizedType.getActualTypeArguments();
            log.trace("日志：typeArray={}", typeArray);
            if (typeArray != null && typeArray.length > 0) {
                clazz = (Class<T>) typeArray[0];
            }
        }
    }

    @Pointcut("@annotation(org.micode.common.annotation.SysLog)")
    public void pointCutForLog() {
        log.debug("pointCutForLog()");
    }

    @Around("pointCutForLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.trace("保存日志：{}", point);
        long beginTime = System.currentTimeMillis();

        String token = sysLogSaver.getCurrentUserToken(point.getArgs());

        //执行方法
        Object result = point.proceed();
        //执行时长(毫秒)
        long endTime = System.currentTimeMillis();
        long time = endTime - beginTime;

        try {
            //保存日志
            saveSysLog(point, time);
        } catch(Exception e) {
            log.warn("Exception when saving log", e);
        }

        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        T sysLogVO = BeanExtUtils.instantiateClass(clazz);
        SysLog syslog = method.getAnnotation(SysLog.class);
        if(syslog != null){
            //注解上的描述
            sysLogVO.setOperationMode(syslog.operationMode());
            String logValue = I18nMsgHelper.replaceByBraces(syslog.value().trim());
            sysLogVO.setOperation(logValue);
        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLogVO.setMethod(className + "." + methodName + "()");

        sysLogVO.setParams(sysLogSaver.getParams(joinPoint.getArgs()));
        sysLogVO.setOriginateApp(sysLogSaver.getLoginApp(joinPoint.getArgs()));
        sysLogVO.setOriginateIp(sysLogSaver.getRemoteIp(joinPoint.getArgs()));
        sysLogVO.setUserId(sysLogSaver.getCurrentUserId(joinPoint.getArgs()));
        sysLogVO.setUserToken(sysLogSaver.getCurrentUserToken(joinPoint.getArgs()));
        sysLogVO.setUserType(sysLogSaver.getUserType(joinPoint.getArgs()));
        sysLogVO.setConsumeMs(time);

        //保存系统日志
        sysLogSaver.save(sysLogVO);
    }

}
